package com.xs.aifitnessagent.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xs.aifitnessagent.entities.Message;
import com.xs.aifitnessagent.mapper.MessageMapper;
import com.xs.aifitnessagent.service.MessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 消息服务实现类
 *
 * @author lambor
 */
@Service
@Slf4j
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {

    @Override
    public Message saveMessage(String chatId, String userId, String content, String messageType, String modelName) {
        Message message = new Message();
        message.setChatId(chatId);
        message.setUserId(userId);
        message.setContent(content);
        message.setMessageType(messageType);
        message.setIsEdited(0);

        // 仅助手消息需要设置模型名称
        if ("ASSISTANT".equals(messageType)) {
            message.setModelName(modelName);
        }

        this.save(message);

        if ("USER".equals(messageType)) {
            log.info("保存用户消息：chatId={}, userId={}, messageId={}", chatId, userId, message.getId());
        } else if ("ASSISTANT".equals(messageType)) {
            log.info("保存助手消息：chatId={}, userId={}, messageId={}, model={}", chatId, userId, message.getId(), modelName);
        } else {
            log.info("保存消息：chatId={}, userId={}, messageId={}, type={}", chatId, userId, message.getId(), messageType);
        }

        return message;
    }

    @Override
    public List<Message> getMessagesByChatId(String chatId, String userId) {
        LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Message::getChatId, chatId)
               .eq(Message::getUserId, userId)
               .orderByAsc(Message::getCreateTime);

        List<Message> allMessages = this.list(wrapper);

        // 去重处理：对于相同内容和类型的消息，只保留最新的一条
        Map<String, Message> uniqueMessages = new LinkedHashMap<>();

        for (Message message : allMessages) {
            String key = message.getContent() + "_" + message.getMessageType();

            // 如果已存在相同内容的消息
            if (uniqueMessages.containsKey(key)) {
                Message existingMessage = uniqueMessages.get(key);

                // 优先保留编辑过的消息，或者保留创建时间更晚的消息
                if (message.getIsEdited() > existingMessage.getIsEdited() ||
                    (message.getIsEdited().equals(existingMessage.getIsEdited()) &&
                     message.getCreateTime().after(existingMessage.getCreateTime()))) {
                    uniqueMessages.put(key, message);
                }
            } else {
                uniqueMessages.put(key, message);
            }
        }

        List<Message> messages = new ArrayList<>(uniqueMessages.values());
        log.info("获取消息列表：chatId={}, userId={}, 原始count={}, 去重后count={}",
                chatId, userId, allMessages.size(), messages.size());

        return messages;
    }

    @Override
    public Message editUserMessage(Long messageId, String newContent, String userId) {
        // 首先获取原消息
        Message originalMessage = this.getById(messageId);
        if (originalMessage == null) {
            throw new RuntimeException("消息不存在");
        }
        
        // 验证是否为该用户的消息
        if (!originalMessage.getUserId().equals(userId)) {
            throw new RuntimeException("无权限编辑此消息");
        }
        
        // 验证是否为用户消息
        if (!"USER".equals(originalMessage.getMessageType())) {
            throw new RuntimeException("只能编辑用户消息");
        }
        
        // 更新消息
        LambdaUpdateWrapper<Message> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Message::getId, messageId)
                    .set(Message::getContent, newContent)
                    .set(Message::getIsEdited, 1)
                    .set(Message::getUpdateTime, new Date());
        
        // 如果是第一次编辑，保存原始内容
        if (originalMessage.getIsEdited() == 0) {
            updateWrapper.set(Message::getOriginalContent, originalMessage.getContent());
        }
        
        this.update(updateWrapper);
        
        // 返回更新后的消息
        Message updatedMessage = this.getById(messageId);
        log.info("编辑用户消息：messageId={}, userId={}", messageId, userId);
        return updatedMessage;
    }

    @Override
    public void deleteMessagesByChatId(String chatId, String userId) {
        LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Message::getChatId, chatId)
               .eq(Message::getUserId, userId);

        int count = (int) this.count(wrapper);
        this.remove(wrapper);
        log.info("删除聊天消息：chatId={}, userId={}, count={}", chatId, userId, count);
    }

    @Override
    public int deleteMessagesAfter(Long messageId, String chatId, String userId) {
        // 首先获取指定消息
        Message targetMessage = this.getById(messageId);
        if (targetMessage == null) {
            throw new RuntimeException("指定的消息不存在");
        }

        // 验证消息所有权
        if (!targetMessage.getUserId().equals(userId)) {
            throw new RuntimeException("无权限操作此消息");
        }

        // 验证消息所属聊天
        if (!targetMessage.getChatId().equals(chatId)) {
            throw new RuntimeException("消息不属于指定的聊天");
        }

        // 删除该消息之后创建的所有消息（基于创建时间）
        LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Message::getChatId, chatId)
               .eq(Message::getUserId, userId)
               .gt(Message::getCreateTime, targetMessage.getCreateTime());

        int count = (int) this.count(wrapper);
        if (count > 0) {
            this.remove(wrapper);
            log.info("删除指定消息之后的消息：messageId={}, chatId={}, userId={}, deletedCount={}",
                    messageId, chatId, userId, count);
        } else {
            log.info("没有找到需要删除的后续消息：messageId={}, chatId={}, userId={}",
                    messageId, chatId, userId);
        }

        return count;
    }
}